package cn.edu.zufe.mjt;

import org.springframework.transaction.annotation.Transactional;

import java.sql.Connection;
import java.sql.SQLException;


/**
 * @author 蒙锦涛
 * @date 2025/6/10
 * @description 从动态代理的角度看Spring 的事务AOP
 */

interface MyService {
	void doSomething() throws SQLException;
}

/**
 * 例如这是我们编写的实现类，并在方法上添加了事务注解
 */
public class MyServiceImpl implements MyService {
	@Transactional(rollbackFor = RuntimeException.class)
	public void doSomething() {
		// 比如插入数据库操作
	}
}

/**
 * 那么当spring真正执行的时候，实际上是通过AOP动态代理，来真正地执行方法
 *
 */
class MyService$proxy1 implements MyService {
	MyService myService;

	/**
	 *  实际上外层给你包装类一个try catch，在之前开启事务，成功执行之后提交，出现异常则回滚。
	 *  无论怎么包装，原理都是一样的，永远要有一个真正执行的方法。
	 *  八股文里几个经典的事务失效场景：
	 *  1. 比如抛出了非RuntimeException的异常，事务不会回滚，因为 try catch 只捕获了 RuntimeException。
	 *  2. 在方法内部进行了 try catch把异常捕获然后不抛出，那么外层的 try catch 也不会捕获到异常，事务也不会回滚。
	 *  3. 以及同类方法之间互相调用，事务失效。因为没有走动态代理
	 *
	 *  <h1>因此，事务失效的本质原因，就是动态代理没有生效，或者生效了没有走正常的逻辑</h1>
	 * @throws SQLException
	 */
	@Override
	public void doSomething() throws SQLException {
		Connection connection = getConnection();
		try {
			connection.setAutoCommit(false);
			// begin transaction
			myService.doSomething(); // 真正执行的时候我们的方法只在这里有一句
			// commit transaction
			connection.commit();
		} catch (RuntimeException e) {
			connection.rollback();
		}
	}

	private Connection getConnection() {
		return null;
	}
}
